package com.kinghood.productcenter.service.base.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kinghood.infrastructure.api.authority.DirectionRemoteVO;
import com.kinghood.infrastructure.api.authority.DirectionReqRemoteDTO;
import com.kinghood.infrastructure.api.authority.SysLogModuleEnum;
import com.kinghood.infrastructure.api.authority.UserRemoteVo;
import com.kinghood.infrastructure.model.KingHoodException;
import com.kinghood.infrastructure.model.constant.CommonConstants;
import com.kinghood.infrastructure.model.enums.StatusEnum;
import com.kinghood.infrastructure.util.base.IdGenUtil;
import com.kinghood.infrastructure.util.UserUtil;
import com.kinghood.infrastructure.util.excel.EasyExcelUtil;
import com.kinghood.productcenter.common.api.authority.SystemDirectionRemote;
import com.kinghood.productcenter.common.api.authority.UserRemote;
import com.kinghood.productcenter.common.model.dao.base.BaseLabelDO;
import com.kinghood.productcenter.common.model.dao.base.BaseLabelItemDO;
import com.kinghood.infrastructure.model.dto.StatusReqDTO;
import com.kinghood.productcenter.common.model.dao.product.DownloadCenterDO;
import com.kinghood.productcenter.common.model.dto.base.LabelItemReqDTO;
import com.kinghood.productcenter.common.model.dto.base.LabelReqDTO;
import com.kinghood.productcenter.common.model.dto.base.ListLabelQueryDTO;
import com.kinghood.productcenter.common.model.excel.LabelExcel;
import com.kinghood.productcenter.common.model.vo.base.*;
import com.kinghood.productcenter.common.utils.UserNameUtil;
import com.kinghood.productcenter.dao.base.BaseLabelMapper;
import com.kinghood.productcenter.service.async.IAsyncHuaWeiYunService;
import com.kinghood.productcenter.service.base.IBaseLabelItemService;
import com.kinghood.productcenter.service.base.IBaseLabelService;
import com.kinghood.productcenter.service.product.IDownloadCenterService;
import com.kinghood.productcenter.service.product.handler.ProductBaseHandler;
import com.kinghood.sharding.model.BasePage;
import com.kinghood.sharding.model.KingHoodPageUtil;
import com.kinghood.sharding.model.KingPageResult;
import com.kinghood.sharding.model.PageResponseVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 基础选项-标签表 服务实现类
 * </p>
 *
 * @author KingHood
 * @since 2023-12-20
 */
@Service
public class BaseLabelServiceImpl extends ServiceImpl<BaseLabelMapper, BaseLabelDO> implements IBaseLabelService {
    @Resource
    private IBaseLabelItemService itemService;
    @Value("${base.uploadPath}")
    private String uploadPath;
    @Resource
    private UserRemote userRemote;
    @Resource
    private SystemDirectionRemote directionRemote;
    @Resource
    private IDownloadCenterService downloadCenterService;
    @Resource
    private IAsyncHuaWeiYunService asyncUploadHuaWeiYun;

    /**
     * 列表
     *
     * @param param 参数
     * @return @return {@link PageResponseVO }
     * @author jp
     * @date 2024/01/12 14:56
     */
    @Override
    public PageResponseVO listLabel(ListLabelQueryDTO param) {
        Page<LabelListVO> result = this.baseMapper.listLabel(KingHoodPageUtil.getPage(param, param), param);

        DirectionReqRemoteDTO directionReqRemoteDTO = new DirectionReqRemoteDTO();
        List<String> codeList = new ArrayList<>();
        codeList.add("label_type");
        directionReqRemoteDTO.setDataCodeList(codeList);
        List<DirectionRemoteVO> directionRemoteList = directionRemote.getDirectionByCodeList(directionReqRemoteDTO);
        Map<String, DirectionRemoteVO> labelTypeMap = null;
        if (!CollectionUtils.isEmpty(directionRemoteList)) {
            labelTypeMap = directionRemoteList.stream().collect(Collectors.toMap(DirectionRemoteVO::getDataKey, i -> i, (x,y) -> x));
        }

        Set<Long> userIdList = new HashSet<>();
        for (LabelListVO record : result.getRecords()) {
            userIdList.add(record.getCreateUserId());
            userIdList.add(record.getUpdateUserId());
            // 设置标签类型
            if (Objects.nonNull(labelTypeMap)) {
                record.setLabelTypeName(labelTypeMap.get(String.valueOf(record.getLabelTypeId())).getDataValue());
            }
            record.setStatusTxt(StatusEnum.getNameByStatus(record.getStatus()));
        }
        userIdList.remove(null);
        if (!CollectionUtils.isEmpty(userIdList)) {
            Map<Long, UserRemoteVo> userMap = userRemote.getUserByIds(new ArrayList<Long>(userIdList));
            for (LabelListVO record : result.getRecords()) {
                record.setCreateUserName(UserNameUtil.getName(record.getCreateUserId(), userMap));
                record.setUpdateUserName(UserNameUtil.getName(record.getUpdateUserId(), userMap));
            }
        }
        return KingPageResult.getResult(result);
    }

    /**
     * 标签下拉
     *
     * @return @return {@link List }<{@link LabelSelectVO }>
     * @author jp
     * @date 2024/01/12 14:56
     */
    @Override
    public List<LabelSelectVO> getAllLabel() {
        List<LabelSelectVO> labelSelectVOS = this.baseMapper.getAllLabel();
        Map<Long, List<LabelItemVO>> itemMap = itemService.lambdaQuery()
                .eq(BaseLabelItemDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(BaseLabelItemDO::getStatus, CommonConstants.ENABLE)
                .list().stream().map(i -> {
            LabelItemVO vo = new LabelItemVO();
            BeanUtils.copyProperties(i, vo);
            return vo;
        }).collect(Collectors.groupingBy(LabelItemVO::getLabelId));
        for (LabelSelectVO label : labelSelectVOS) {
            label.setItem(itemMap.get(label.getId()));
        }
        return labelSelectVOS;
    }

    /**
     * 添加或更新
     *
     * @param param 参数
     * @return
     * @author jp
     * @date 2024/01/12 14:56
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addOrUpdateLabel(LabelReqDTO param) {
        LocalDateTime now = LocalDateTime.now();
        checkLabelOnly(param);
        checkItemOnly(param);
        BaseLabelDO label = new BaseLabelDO();
        List<BaseLabelItemDO> newItems = new ArrayList<>();
        List<BaseLabelItemDO> oldItems = new ArrayList<>();
        BeanUtils.copyProperties(param, label);
        if (Objects.isNull(param.getId())) {
            label.setId(IdGenUtil.get().nextId())
                    .setCreateTime(now)
                    .setCreateUserId(UserUtil.getUserId())
                    .setIsDelete(CommonConstants.IS_DELETE_N);
            this.save(label);
        } else {
            label.setUpdateTime(now);
            label.setUpdateUserId(UserUtil.getUserId());
            this.updateById(label);
            // 要保留的标签值id
            List<Long> updateIds = param.getItems().stream().filter(i -> Objects.nonNull(i.getId())).map(i -> i.getId()).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(updateIds)) {
                int count = this.baseMapper.countLabelValueUnused(param.getId(), updateIds);
                if (count > 0) {
                    throw new KingHoodException(-1, "当前标签正在使用中，请删除使用商品后再重试");
                }
            }

            itemService.lambdaUpdate().set(BaseLabelItemDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                    .set(BaseLabelItemDO::getUpdateTime, now)
                    .set(BaseLabelItemDO::getUpdateUserId, UserUtil.getUserId())
                    .eq(BaseLabelItemDO::getLabelId, param.getId())
                    .notIn(!CollectionUtils.isEmpty(updateIds), BaseLabelItemDO::getId, updateIds)
                    .update();
        }
        for (LabelItemReqDTO item : param.getItems()) {
            BaseLabelItemDO labelItem = new BaseLabelItemDO();
            BeanUtils.copyProperties(item, labelItem);
            if (Objects.isNull(item.getId())) {
                // 新增
                labelItem.setId(IdGenUtil.get().nextId())
                        .setLabelId(label.getId())
                        .setLabelCode(label.getLabelCode())
                        .setCreateTime(now)
                        .setCreateUserId(UserUtil.getUserId())
                        .setIsDelete(CommonConstants.IS_DELETE_N);
                newItems.add(labelItem);
                // 强制在新增时排序
                now = now.plusSeconds(1);
            } else {
                labelItem.setUpdateTime(LocalDateTime.now())
                        .setUpdateUserId(UserUtil.getUserId());
                oldItems.add(labelItem);
            }
        }
        itemService.saveBatch(newItems);
        itemService.updateBatchById(oldItems);
    }

    /**
     * 详细
     *
     * @param id 身份证件
     * @return @return {@link LabelReqDTO }
     * @author jp
     * @date 2024/01/12 14:56
     */
    @Override
    public LabelReqDTO detailLabel(Long id) {
        BaseLabelDO label = this.lambdaQuery().eq(BaseLabelDO::getId, id)
                .eq(BaseLabelDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .one();
        if (Objects.nonNull(label)) {
            LabelReqDTO result = new LabelReqDTO();
            BeanUtils.copyProperties(label, result);
            List<LabelItemReqDTO> items = itemService.lambdaQuery()
                    .eq(BaseLabelItemDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .eq(BaseLabelItemDO::getLabelId, id)
                    .list()
                    .stream().map(i -> {
                        LabelItemReqDTO item = new LabelItemReqDTO();
                        BeanUtils.copyProperties(i, item);
                        return item;
                    }).collect(Collectors.toList());
            result.setItems(items);
            return result;
        }
        return null;
    }

    /**
     * 更新状态
     *
     * @param param 参数
     * @return
     * @author jp
     * @date 2024/01/12 14:56
     */
    @Override
    public void updateLabelStatus(StatusReqDTO param) {
        this.lambdaUpdate().set(BaseLabelDO::getStatus, param.getStatus())
                .set(BaseLabelDO::getUpdateTime, LocalDateTime.now())
                .set(BaseLabelDO::getUpdateUserId, UserUtil.getUserId())
                .eq(BaseLabelDO::getId, param.getId())
                .eq(BaseLabelDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .update();
    }

    /**
     * 检查是否唯一
     *
     * @param param 参数
     * @author jp
     * @date 2023/12/21
     */
    private void checkLabelOnly(LabelReqDTO param){
        Long count;
        if (Objects.isNull(param.getId())) {
            count = this.lambdaQuery().eq(BaseLabelDO::getLabelCode, param.getLabelCode())
                    .eq(BaseLabelDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .count();
            if (count > 0) {
                throw new KingHoodException(-1 ,"编码已存在");
            }
            count = this.lambdaQuery().eq(BaseLabelDO::getLabelCode, param.getLabelCode())
                    .eq(BaseLabelDO::getLabelName, param.getLabelName())
                    .eq(BaseLabelDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .count();
            if (count > 0) {
                throw new KingHoodException(-1 ,"名称已存在");
            }
        } else {
            count = this.lambdaQuery().eq(BaseLabelDO::getLabelCode, param.getLabelCode())
                    .ne(BaseLabelDO::getId, param.getId())
                    .eq(BaseLabelDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .count();
            if (count > 0) {
                throw new KingHoodException(-1 ,"编码已存在");
            }
            count = this.lambdaQuery().eq(BaseLabelDO::getLabelCode, param.getLabelCode())
                    .ne(BaseLabelDO::getId, param.getId())
                    .eq(BaseLabelDO::getLabelName, param.getLabelName())
                    .eq(BaseLabelDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .count();
            if (count > 0) {
                throw new KingHoodException(-1 ,"名称已存在");
            }
        }
    }

    /**
     * 检查标签值唯一
     *
     * @param label 标签
     * @author jp
     * @date 2023/12/21
     */
    private void checkItemOnly(LabelReqDTO label) {
        long size = label.getItems().size();
        long codeSize = label.getItems().stream().map(i -> i.getItemCode()).distinct().count();
        if (codeSize < size) {
            throw new KingHoodException(-1 ,"存在重复编码");
        }
        long nameSize = label.getItems().stream().map(i -> i.getItemValue()).distinct().count();
        if (nameSize < size) {
            throw new KingHoodException(-1 ,"存在重复名称");
        }
    }

    /**
     * 下载标签
     *
     * @param param    参数
     * @param response 回答
     * @author jp
     * @date 2024/01/04
     */
    @Override
    public void downloadLabel(ListLabelQueryDTO param, HttpServletResponse response) {
        String fileName = StringUtils.isEmpty(param.getFileName()) ? "标签数据" : param.getFileName();
        String sheetName = StringUtils.isEmpty(param.getSheetName()) ? "标签" : param.getSheetName();

        if (Objects.isNull(param.getPage())) {
            param.setPage(new BasePage());
            param.getPage().setPageSize(99999);
        }
        PageResponseVO responseVO = listLabel(param);
        List<LabelListVO> dataList = responseVO.getList();
        List<LabelExcel> result = new ArrayList<>();
        for (LabelListVO listVO : dataList) {
            LabelExcel excel = new LabelExcel();
            BeanUtils.copyProperties(listVO, excel);
            result.add(excel);
        }
        // 保存到数据库
        LocalDateTime now = LocalDateTime.now();
        DownloadCenterDO downloadCenterDO = new DownloadCenterDO();
        try {
            String showParam = "";
            if (!CollectionUtils.isEmpty(param.getDownloadField())) {
                showParam = String.join(",", param.getDownloadField());
            }
            String path = EasyExcelUtil.export(response, fileName, sheetName, result, LabelExcel.class,
                    showParam, uploadPath);
            File file = new File(path);
            downloadCenterDO.setId(IdGenUtil.getId())
                    .setFileName(file.getName())
                    .setModule(SysLogModuleEnum.PRODUCT_LABEL.getType())
                    .setType(2)
                    .setFileSize(ProductBaseHandler.getSizeName(file.length()))
                    .setUrl(path)
                    .setCreateTime(now)
                    .setUpdateTime(now)
                    .setCreateUserId(UserUtil.getUserId())
                    .setUpdateUserId(UserUtil.getUserId());
            downloadCenterService.save(downloadCenterDO);
            asyncUploadHuaWeiYun.uploadToHuaWeiYun(downloadCenterDO.getId(), file.getAbsolutePath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
